/**
 * JavaScript Integration Framework
 * License LGPL(您可以在任何地方免费使用,但请不要吝啬您对框架本身的改进)
 * http://www.xidea.org/project/jsi/
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * @author: dawei jin(jindw@xidea.org)
 * @author: DSONet (dsonet@msn.com)
 * @version $Id: jsi.js 47 2008-06-23 18:26:39Z dsonet@gmail.com $
 */
/**
 * JSI对象
 * @type {object}
 * @public
 */
var $JSI = {
	/**
	 * 启动脚本的根路径，根据启动脚本文件名自动探测。
	 * @public
	 * @id $JSI.bootBase
	 * @type {string}
	 * @static
	 */
	//bootBase : "http://localhost:8080/boot/"
	/**
	 * 包加载的根路径，默认同启动脚本根路径。
	 * @public
	 * @id $JSI.scriptBase
	 * @type {string}
	 * @static
	 * @deprecated
	 */
	//,scriptBase : "http://localhost:8080/libs/"
	/**
	 * 包加载的根路径，默认同启动脚本根路径。
	 * @public
	 * @id $JSI.libBase
	 * @type {string}
	 * @static
	 */
	//,libBase : "http://localhost:8080/libs/"
};
if ("org.xidea.jsi.boot:$log") 
{
	/**
	 * 全局日志
	 * <p>JSI 可选功能,也可以使用JSA将代码中的日志处理信息清除。<p>
	 * <p>自JSI2.1之后，只有全局日志，没有装载单元日志了。<p>
	 * @param {mixed} arg 要打印的对象
	 * @arguments {mixed} args ... 要打印的对象
	 * @type {Function}
	 * @public
	 */
	var $log;//将在$import 闭包中初始化
}
/**
 * 导入指定元素（脚本、函数、类、变量）至指定目标,默认方式为同步导入，默认目标为全局对象（Global == window(html)）。
 * <pre class="code"><code>
 *   $import("com.yourcompany.ClassA")//即时装载--通过指定对象
 *   $import("com/yourcompany/class-a.js")//即时装载--通过指定文件
 *   $import("example.ClassA",MyNamespace)//指定装载目标
 *   $import("example.ClassA",function(ClassA){
 *   $log("callback:"+ClassA)})//异步装载
 *   $import("example/class-a.js",true)//延迟装载(可获得良好特性,需要编译支持或者服务端支持)
 * </code></pre>
 * <h3>实现步骤：</h3>
 * <ul>
 *   <li>若元素未装载或依赖未装载，且为异步装载模式，先缓存需要的脚本资源</li>
 *   <li>若元素未装载或依赖未装载，且为同步非阻塞装载模式，打印预装载脚本（当前script标签的其他脚本<b>可能</b>继续运行，浏览器不同表现略有不同）;
 *	并且等待预装载脚本执行之后继续以下步骤</li>
 *   <li>若元素未装载或依赖未装载，装载之</li>
 *   <li>将该元素声明为指定目标的属性(默认目标为全局对象，这时相当于声明了全局变量)</li>
 * </ul>
 * <h3>全局对象的特殊性说明:</h3>
 * <ul>
 *   <p>全局对象的属性同时也是全局变量，可以在任何地方直接使用，<br/>
 *	也就是说：<br/>
 *	$import函数调用时，默认（未指定target）导入成全局对象属性，等价于声明了一个全局变量。</p>
 * </ul>
 * <p>
 *   <i><b>该方法为最终用户设计（页面上的脚本）,不推荐类库开发者（托管脚本）使用该函数,除非确实需要（如需要动态导入时）。类库开发者可在包中定义脚本依赖完成类似功能。</b></i>
 * </p>
 * @public
 * @param {String} path (package:Object|package.Object|package:*|package.*| scriptPath)
 * @param {Object} target 可选参数，指定导入容器。
 *					当该参数为有效对象时(instanceof Object && not instanceof Function)，导入的元素将赋值成其属性；
 *					当该参数为boolean型或函数(typeof target in ['boolean','function'])且未指定第三个参数时，将其当做第三个参数，而target本身等价为未指定；
 *					当该参数未指定时，target为全局变量容器,这种情况等价于直接声明的全局变量。
 * @param {Function|Boolean} col callbackOrLazyLoad 可选参数,默认为null。
 *					如果其值为函数，表示异步导入模式；
 *					如果其值为真，表示延迟同步导入模式，否则为即时同步导入（默认如此）。
 * @return {Package|Object|void} 用于即时导入时返回导入的对象
 *					<ul>
 *					  <li>导入单个对象时:返回导入对象;</li>
 *					  <li>导入文件或者多个对象(*)时:返回导入目标;</li>
 *					  <li>导入包时:返回包对象;</li>
 *					</ul>
 *					<p>一般可忽略返回值.因为默认情况下,导入为全局变量;无需再显示申明了.</p>
 */
var $import = function(freeEval, cachedScripts)
{
	if ("org.xidea.jsi.boot:$log") 
	{
		/**
		 * 全局日志
		 * <p>JSI 可选功能,也可以使用JSA将代码中的日志处理信息清除。<p>
		 * <p>自JSI2.1之后，只有全局日志，没有装载单元日志了。<p>
		 * @param {mixed} arg 要打印的对象
		 * @arguments {mixed} args ... 要打印的对象
		 * @public
		 */
		$log = function()
		{
			var i = 0, args = arguments, argsLen = args.length, temp = [];
			
			if (this == $log) 
			{
				var bindLevel = args[i++], levelName = args[i++], d = new Date;
				temp.push(levelName + " " + d.toLocaleString() + ":" + d.getMilliseconds() + "\n");
			}
			
			while (i < argsLen) 
			{
				var msg = args[i++], n;
				
				if (typeof msg == "object" && msg != null) 
				{
					temp.push(msg + "{");
					
					for (n in msg) 
					{
						temp.push(n + ": " + msg[n]);
					}
					temp.push("}");
				}
				else 
				{
					temp.push(msg);
				}
			}
			
			temp = temp.join('\n');
			bindLevel >= 0 ? isConsole ? "trace" != levelName && console[levelName] ? console[levelName](temp) : console.log(temp) : isOpera ? opera.postError(temp) : !confirm(temp + "\ncontinue to show " + levelName + " log?") ? consoleLevel = bindLevel + 1 : 0 : alert(temp);
		}
		/**
		 * 设置日志级别
		 * 默认级别为debug
		 * @param {String|Number} level 日志级别
		 * @protected
		 */
		$log.setLevel = function(level)
		{
			if (logLevelNameMap[level]) 
			{
				consoleLevel = level;
			}
			else 
			{
				var i = logLevelNameMap.length;
				level = level.toLowerCase();
				
				while (i--) 
				{
					if (logLevelNameMap[i] == level) 
					{
						consoleLevel = i;
						return;
					}
				}
				$log("unknow logLevel:" + level);
			}
		};
		/**
		 * 日志处理函数
		 * @param {Number} bindLevel 绑定函数的输出级别，只有该级别大于等于输出级别时，才可输出日志
		 * @param {String} bindName 日志级别
		 * @return {Function}
		 * @internal
		 */
		function buildLevelLog(bindLevel, bindName)
		{
			return function()
			{
				if (bindLevel >= consoleLevel) 
				{
					var msg = [bindLevel, bindName];
					msg.push.apply(msg, arguments);
					$log.apply($log, msg);
				}
			}
		}
		/**
		 * 日志级别集合
		 * @type {Array,String}
		 * @internal
		 */
		var logLevelNameMap = ["trace", "debug", "info", "warn", "error", "fatal"];
		/**
		 * 默认控制台日志级别
		 * @type {Number}
		 * @internal
		 */
		var consoleLevel = 1;
		/**
		 * 默认控制台日志级别
		 * @type {Number}
		 * @internal
		 */
		var isConsole = typeof console != "undefined" && console.log;
		/**
		 * 是否为opera浏览器
		 * @type {Boolean}
		 * @internal
		 */
		var isOpera = typeof opera != "undefined";

		var logLevelIndex = logLevelNameMap.length;

		while (logLevelIndex--) 
		{
			var logName = logLevelNameMap[logLevelIndex];
			$log[logName] = buildLevelLog(logLevelIndex, logName);
		};
		buildLevelLog = logLevelIndex = logName = null;
	}

	/**
	 * 包对象集合
	 * @type {object}
	 * @internal
	 */
	var packageMap = {};

	/**
	 * 包名映射集合
	 * @type {object}
	 * @internal
	 */
	var mappedPath = 
	{
		YAHOO: "com.yahoo.yui:YAHOO",
		Ext: "com.extjs:Ext",
		jQuery: "com.jquery",
		Prototype: "org.prototypejs",
		Scriptaculous: "org.scriptaculous"
	};
	/**
	 * 是否为文件访问模式
	 * @type {boolean}
	 * @internal
	 */
	var isLocal = location.protocol == 'file:';
	/**
	 * 引导文件地址
	 * @type {string}
	 * @internal
	 */
	var bootBase = $JSI.bootBase;
	
	if (!bootBase) 
	{
		bootBase = document.getElementsByTagName('script');
		$JSI.bootBase = bootBase = bootBase[bootBase.length - 1].src.replace(/[^\/\\]+([\?#].)*$/, "");
	}
	/**
	 * 包文件地址
	 * @type {string}
	 * @internal
	 */
	var libBase = $JSI.scriptBase = $JSI.libBase = $JSI.libBase || bootBase;
	/**
	 * 包名转换
	 * @public
	 * @param {String} map 映射名
	 * @param {String} path 实际路径
	 * @id $JSI.mapPath
	 */
	$JSI.mapPath = function(map, path)
	{
		mappedPath[map] = path;
	};
	/**
	 * 设置包所在地址
	 * @public
	 * @param {String} libBase 包地址
	 * @id $JSI.setLibBase
	 */
	$JSI.setLibBase = function(sBase)
	{
		libBase = sBase + (sBase.charAt(sBase.length) == "/" ? "" : "/");
	};
	/**
	 * 缓存脚本,当无参数时则返回已缓存的脚本集合.
	 * @public
	 * @param {String} pkg 包名称
	 * @param {String|Object} file2dataMap 文件相对路径或缓存文件集合
	 * @param {String|Function} value 缓存函数或文本
	 * @return {void|Object}
	 */
	$JSI.preload = function(pkg, file2dataMap, value)
	{
		if (arguments.length < 1)
		{
			return cachedScripts;
		}
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.trace("addCacheScript: pkg: " + pkg + "fileName:" + file2dataMap);
			}
		}
		//若已存在包缓存集,则直接赋值
		if (cachedScripts[pkg]) 
		{
			pkg = cachedScripts[pkg];
			if (value == null) 
			{
				for (var n in file2dataMap) 
				{
					pkg[n] = file2dataMap[n];
				}
			}
			else 
			{
				pkg[file2dataMap] = value;
			}
		}
		//否则建立该包的缓存集
		else 
		{
			value == null ? cachedScripts[pkg] = file2dataMap : (cachedScripts[pkg] = {})[file2dataMap] = value;
		}
	};
	
	if ("org.xidea.jsi.boot:col") 
	{
		/**
		 * 异步加载队列
		 * @instance Array
		 * @internal
		 */
		var lazyTaskList = [];
		/**
		 * 异步加载触发脚本,若为ie,则使用常规src方式
		 * @type {string}
		 * @internal
		 */
		var lazyScript = "<script type=\"text/javascript\" src='data:text/javascript,$import()'></script>";
		/**
		 * 缓存文件集合
		 * @type {object}
		 * @internal
		 */
		var cacheFileMap = {};
		
		/**
		 * 缓存清单计算
		 * @param {Package} packageObject 包对象
		 * @param {String} file 文件名
		 * @param {String} object 对象名称
		 * @internal
		 */
		function appendCacheFiles(packageObject, file, object)
		{
			packageObject.initialize && packageObject.initialize();
			//得到文件完整路径+文件名
			var path = packageObject.name.replace(/\.|$/g, '/') + file;
			//脚本文件装载状态数据[装载状态, 脚本是否无需再缓存]
			var data = cacheFileMap[path];
			var loader = packageObject.loaderMap[file];
			//若已经加入过文件缓存表
			if (data) 
			{
				//无需再与装载系统同步
				if (data[0]) 
				{
					return;
				}
				else 
				{
					if (object) 
					{
						if (data[object]) 
						{
							//has loaded
							return;
						}
						else 
						{
							//set load status: complete
							data[object] = 1;
						}
					}
					else 
					{
						//set load status: complete
						data[0] = 1;
					}
				}
			}
			else 
			{
				//未装载，先用实际装载的信息填充之
				cacheFileMap[path] = data = [];

				//更新该装载节点状态为已装载
				data[object || 0] = 1;

				data[1] = getCachedScript(packageObject.name, file) == null ? loader : 1;//==null,缓存库已经存在
			}

			if (loader) 
			{
				if (deps = loader.dependenceMap) 
				{
					if (object) 
					{
						var deps = deps[object];
						var i = deps && deps.length;

						while (i--) 
						{
							var dep = deps[i];
							appendCacheFiles(dep[0], dep[1], dep[2]);
						}
					}

					for (object in deps) 
					{
						var deps2 = deps[object];
						var i = deps2.length;

						while (i--) 
						{
							var dep = deps2[i];
							appendCacheFiles(dep[0], dep[1], dep[2]);
						}
					}
				}
				else 
				{
					//没有依赖，标识为全部装载完成
					data[0] = 1;
				}
			}
			else 
			{
				var deps = packageObject.dependenceMap[file];
				var i = deps && deps.length;
				while (i--) 
				{
					var dep = deps[i];
					var key = dep[3];
					if (!object || !key || object == key) 
					{
						appendCacheFiles(dep[0], dep[1], dep[2]);
					}
				}
			}
		}
	}
	/**
	 * 获取脚本缓存。
	 * @internal
	 * @param {Package} pkg 包对象
	 * @param {String} fileName 文件名
	 * @return {String|Function}
	 */
	function getCachedScript(pkg, fileName)
	{
		var pos;
		if (fileName && (pos = fileName.lastIndexOf('/')) > -1) 
		{
			pkg += "." + fileName.substring(0, pos).replace(/\//g, ".");
			fileName = fileName.substr(pos + 1);
		}
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.debug("getCachedScript: pkg: " + pkg + " fileName:" + fileName);
			}
		}
		return (pkg = cachedScripts[pkg]) && pkg[fileName];
	};
	
	if (this.ActiveXObject) 
	{
		if ("org.xidea.jsi.boot:col") 
		{
			lazyScript = lazyScript.replace(/'.*'/, "'" + bootBase + "lazy-trigger.js'");
		}
		
		if (!this.XMLHttpRequest || isLocal) 
		{
			var progId = ["MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
			/**
			 * 统一的 XMLHttpRequest 构造器（对于ie，为一个有返回值的构造器（这时new操作返回该返回值），返回它支持的ActiveX控件）
			 * 关于 XMLHttpRequest对象的详细信息请参考
			 * <ul>
			 *   <li><a href="http://www.w3.org/TR/XMLHttpRequest/">W3C XMLHttpRequest</a></li>
			 *   <li><a href="http://www.ikown.com/manual/xmlhttp/index.htm">中文参考</a></li>
			 *   <li><a href="http://msdn2.microsoft.com/en-us/library/ms762757(VS.85).aspx">MSXML</a></li>
			 * </ul>
			 * @id XMLHttpRequest
			 * @return {XMLHttpRequest}
			 * @constructor
			 */
			this.XMLHttpRequest = function()
			{
				var i = progId.length, o, e;
				while (i--) 
				{
					try 
					{
						o = new ActiveXObject(progId[i]);
						progId = progId[i];
						XMLHttpRequest = function()
						{
							return new ActiveXObject(progId);
						}
						return o;
					} 
					catch (e) 
					{
					}
					finally
					{
						!e && (e = i = o = null);
					}
				}
			};
		}
	}
	bootBase = null;
	/**
	 * 包信息数据结构类<b> &#160;(JSI 内部对象，普通用户不可见)</b>.
	 * <p>在包目录下，有个包定义脚本（__package__.js）；
	 * 在包的构造中执行这段脚本，执行中，this指向当前包对象</p>
	 * <p>其中,两个常用方法,<a href="#Package.prototype.addScript">addScript</a>,<a href="#Package.prototype.addDependence">addDependence</a></p>
	 * <p>该对象不应该在任何方修改.</p>
	 * <p>(特殊情况时也可在外部动态构造Package对象).</p>
	 * @public
	 * @constructor
	 * @implicit
	 * @param {String} name 包名（必须为真实存在的包）
	 * @param {String} pscript 定义脚本
	 */
	function Package(name, pscript)
	{
		/**
		 * 包名称
		 * @private
		 * @readonly
		 * @type {string}
		 * @id Package.prototype.name
		 */
		packageMap[this.name = name] = this;
		
		/**
		 * 包脚本路径目录
		 * @private
		 * @readonly
		 * @type {string}
		 */
		this.scriptBase = libBase + (name.replace(/\./g, '/')) + '/';
		/**
		 * 包脚本依赖
		 * 起初作为一个数组对象临时存储依赖信息。
		 * <code>
		 * {[thisPath1,targetPath1,afterLoad],...}</code>
		 * initialize成员方法调用后。
		 * 将变成一个依赖表、且计算完全部包内匹配
		 * <code>
		 * [targetPackage, targetFileName, targetObjectName,thisObjectName, afterLoad, names]
		 * </code>
		 * 该值初始化后为Object实例,且一定不为空.
		 * @private
		 * @readonly
		 * @type {object}
		 */
		this.dependenceMap = [];
		/**
		 * 脚本->装载器表
		 * @private
		 * @readonly
		 * @type {object}
		 */
		this.loaderMap = {};
		/**
		 * 脚本->对象表
		 * object名为类名或包名 如<code>YAHOO</code>
		 * @private
		 * @type {object}
		 * @readonly
		 */
		this.scriptObjectMap = {};
		/**
		 * 对象->脚本表
		 * object名为全名 如<code>YAHOO.ui.Color</code>
		 * @private
		 * @readonly
		 * @type {object}
		 */
		this.objectScriptMap = {};
		/**
		 * 存储顶级对象的表.
		 * 比如yui 顶级对象为 YAHOO
		 * @private
		 * @readonly
		 * @type {object}
		 * @memberOf Package
		 */
		this.objectMap = {};
		
		try 
		{
			pscript instanceof Function ? pscript.call(this) : freeEval.call(this, pscript);
		} 
		catch (e) 
		{
			if (":debug") 
			{
				if ("org.xidea.jsi.boot:$log") 
				{
					$log.error("Package execute error:[" + name + "]\nException:" + e);
				}
			}
			throw e;
		}
	}
	
	Package.prototype = 
	{
	
		/**
		 * 初始化包依赖信息.
		 * @private
		 */
		initialize: function()
		{
			//hack for null
			this.initialize = 0;
			//cache attributes
			var thisObjectScriptMap = this.objectScriptMap;
			var thisScriptObjectMap = this.scriptObjectMap;
			var list = this.dependenceMap;
			var map = {};
			
			var i = list.length;
			
			while (i--) 
			{
				var dep = list[i];
				var thisPath = dep[0];
				var targetPath = dep[1];
				var afterLoad = dep[2];
				
				if (":debug") 
				{
					if (!targetPath) 
					{
						if ("org.xidea.jsi.boot:$log") 
						{
							$log.error(dep.join('\n'));
							$log.error(list.join('\n'));
						}
					}
				}
				
				//循环内无赋值变量声明
				var targetPackage = this;
				//hack for null
				var thisObjectName = 0;
				var targetObjectName = 0;
				var distinctPackage = 0;
				var allSource = "*" == thisPath;
				var allTarget = targetPath.indexOf("*") + 1;
				var fileRe = /[:\.].*/;
				var nsRe = /\..*$/;
				var mp;
				(mp = mappedPath[targetPath.replace(fileRe, "")]) && !thisObjectScriptMap[targetPath.replace(fileRe, "")] && (targetPath = targetPath.replace(/^[^:\.]*/, mp));
				
				if (allSource || allTarget) 
				{
					var targetFileMap;
					
					if (allSource) 
					{
						var thisFileMap = thisScriptObjectMap;
					}
					else 
					{
						var thisFileName = thisObjectScriptMap[thisPath];
						
						thisFileName ? thisObjectName = thisPath : thisFileName = thisPath;

						(thisFileMap = {})[thisFileName] = 0;
					}
					
					if (allTarget) 
					{
						if (allTarget > 1) 
						{
							targetPackage = realPackage(findPackageByPath(targetPath));
							distinctPackage = 1;
						}
						targetFileMap = targetPackage.scriptObjectMap;
					}
					else 
					{
						var targetFileName = thisObjectScriptMap[targetPath];
						
						if (targetFileName) 
						{
							targetObjectName = targetPath;
						}
						else if (thisScriptObjectMap[targetPath]) 
						{
							targetFileName = targetPath;
						}
						else 
						{
							distinctPackage = 1;
							targetPackage = findPackageByPath(targetPath);
							targetPath = targetPath.substring(targetPackage.name.length + 1);
							targetPackage = realPackage(targetPackage);
							var targetFileName = targetPackage.objectScriptMap[targetPath];
							
							targetFileName ? targetObjectName = targetPath : targetFileName = targetPath;
						}
						(targetFileMap = {})[targetFileName] = 0;
					}
					
					for (var targetFileName in targetFileMap) 
					{
						var dep = [targetPackage, targetFileName, targetObjectName, thisObjectName, afterLoad, targetObjectName ? [targetObjectName.replace(nsRe, '')] : targetPackage.scriptObjectMap[targetFileName]]
						
						for (var thisFileName in thisFileMap) 
						{
							if (distinctPackage || thisFileName != targetFileName) 
							{
								(map[thisFileName] || (map[thisFileName] = [])).push(dep);
							}
						}
					}
				}
				else 
				{
				
					var thisFileName = thisObjectScriptMap[thisPath];
					var targetFileName = thisObjectScriptMap[targetPath];
					
					thisFileName ? thisObjectName = thisPath : thisFileName = thisPath;
					
					if (targetFileName) 
					{
						targetObjectName = targetPath;
					}
					else if (thisScriptObjectMap[targetPath]) 
					{
						targetFileName = targetPath;
					}
					else 
					{
						!thisObjectScriptMap[targetPath] && mappedPath[targetPath] && (targetPath = mappedPath[targetPath]);
						targetPackage = findPackageByPath(targetPath);
						targetPath = targetPath.substr(targetPackage.name.length + 1);
						targetPackage = realPackage(targetPackage);
						var targetFileName = targetPackage.objectScriptMap[targetPath];
						
						targetFileName ? targetObjectName = targetPath : targetFileName = targetPath;
					}
					(map[thisFileName] || (map[thisFileName] = [])).push([targetPackage, targetFileName, targetObjectName, thisObjectName, afterLoad, targetObjectName ? [targetObjectName.replace(nsRe, '')] : targetPackage.scriptObjectMap[targetFileName]]);
				}
			}
			
			this.dependenceMap = map;
		},
		
		/**
		 * 添加脚本及其声明的对象（函数、方法名）。
		 * 需要指定脚本位置（必须在当前包目录中），元素名(可用数组，同时指定多个)。
		 * <i>该成员函数只在包定义文件（__package__.js）中调用 </i>
		 * @public
		 * @type {function}
		 * @param {String} scriptPath 指定脚本路径
		 * @param {String|Array} objectNames 字符串或数组,脚本对象声明
		 * @param {String|Array} [beforeLoadDependences] 装载前依赖
		 * @param {String|Array} [afterLoadDependences] 装载后依赖
		 */
		addScript: function(scriptPath, objectNames, beforeLoadDependences, afterLoadDependences)
		{
			//若第一个参数为字符串数组,则自动添加文件名称和对象名称相对应,依赖都相同的脚本声明.
			//若包内的对象和脚本名称一一对应时,可采用此方法快速添加脚本声明.
			if (scriptPath instanceof Array) 
			{
				var i = scriptPath.length, objName;
				while (i--) 
				{
					objName = scriptPath[i];
					this.addScript(objName + ".js", objName, beforeLoadDependences, afterLoadDependences);
				}
			}
			else 
			{
				var objects = this.scriptObjectMap[scriptPath];

				if (objects) 
				{
					var previousObject = objects[objects.length - 1];
				}
				else 
				{
					objects = (this.scriptObjectMap[scriptPath] = []);
				}
				
				if (objectNames) 
				{
					var nsRe = /\..*$/;
					if (objectNames instanceof Array) 
					{
						var i = objectNames.length;
						while (i--)
						{
							var object = objectNames[i];
							this.objectScriptMap[object] = scriptPath;
							//将形如YAHOO.util.Color的对象名称,过滤为YAHOO
							object = object.replace(nsRe, '');
							
							if (previousObject != object) 
							{
								objects.push(previousObject = object);
							}
						}
					}
					else 
					{
						this.objectScriptMap[objectNames] = scriptPath;
						objectNames = objectNames.replace(nsRe, '');
						
						if (previousObject != objectNames) 
						{
							objects.push(objectNames);
						}
					}
				}
				beforeLoadDependences && this.addDependence(scriptPath, beforeLoadDependences);
				afterLoadDependences && this.addDependence(scriptPath, afterLoadDependences, 1);
			}
		},
		/**
		 * 添加脚本依赖。
		 * 需要指定当前脚本文件或者脚本元素位置（必须在当前包目录中）.
		 * 被依赖的脚本文件或者脚本元素位置(当前包中的脚本，或者通过抽象路径指定其他包中的脚本)、
		 * 是否需要执行前导入(装载期依赖)。
		 * <i>该成员函数只在包定义文件（__package__.js）中调用 </i>
		 * @public
		 * @param {String|Array} thisPath 本包中当前脚本文件或者脚本元素，使用*可表示当前该包中已添加全部脚本文件（将逐一添加同样的依赖）。
		 * @param {String|Array} targetPath 依赖的脚本文件抽象路径（可不包括最后的版本包）或者脚本元素抽象路径
		 * @param {Boolean } [afterLoad=false] 可选参数(默认为false) 是否可以执行后导入(运行期依赖)
		 */
		addDependence: function(thisPath, targetPath, afterLoad)
		{
			if (targetPath instanceof Array) 
			{
				var i = targetPath.length;
				
				while (i--) 
				{
					this.addDependence(thisPath, targetPath[i], afterLoad);
				}
			}
			else 
			{
				if ("org.xidea.jsi.boot:dependenceOptimize") 
				{
					if (!afterLoad) 
					{
						thisPath = this.objectScriptMap[thisPath] || thisPath;
					}
				}
				this.dependenceMap.push([thisPath, targetPath, afterLoad]);
			}
		},
		
		/**
		 * 设置具体实现包名,用于版本管理,不常用。
		 * 比如，我们可以给Ext库一个统一的包,
		 * 但是我们的内容都放在具体的实现版本里,
		 * 我们可以通过该设置（setImplementation(".v2_02");）来指定默认的具体实现版本。
		 * <i>该成员函数只在包定义文件（__package__.js）中调用 </i>
		 * @public
		 * @param {String} packagePath 指定实现包名,全路径(ID(.ID)*)或相对路径（"." 开始的为本包下的相对路径）
		 */
		setImplementation: function(packagePath)
		{
			if (packagePath.charAt(0) == '.') 
			{
				packagePath = this.name + packagePath;
				//相对路径处理,移除..部分
				while (packagePath != (packagePath = packagePath.replace(/\w+\.+\//, ''))) 
					;
			}

			this.implementation = packagePath;
		}
	};
	
	/**
	 * 创建一个新的类加载器，加载指定脚本
	 * @internal
	 * @param {Package} packageObject 包对象
	 * @param {String} fileName 指定的脚本文件名
	 * @param {String} object 需要装载的对象 * 代表全部元素
	 */
	function loadScript(packageObject, fileName, object)
	{
		var loader = packageObject.loaderMap[fileName];
		
		if (!loader) 
		{
			if (packageObject.scriptObjectMap[fileName]) 
			{
				packageObject.initialize && packageObject.initialize();
				loader = new ScriptLoader(packageObject, fileName);
			}
			else 
			{
				//TODO: try parent
				if (":debug") 
				{
					if ("org.xidea.jsi.boot:$log") 
					{
						return $log.error('loadScript: load object ' + object + ' in [' + fileName + '] file Not Found at package ' + packageObject.name);
					}
				}
			}
		}

		loader.initialize && loader.initialize(object);
	}
	/**
	 * Dependence 的第二种设计
	 * Dependence = [0			, 1			 , 2			   , 3			,4		 ,5	]
	 * Dependence = [targetPackage, targetFileName, targetObjectName,thisObjectName, afterLoad,names]
	 * @param {Array} data 依赖关系数据[targetPackage, targetFileName, targetObjectName,thisObjectName, afterLoad,names]
	 * @param {Array} vars 变量表
	 */
	function loadDependence(data, vars)
	{
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.debug("loadDependence: ", data, vars);
			}
		}
		loadScript(data[0], data[1], data[2]);
		var objectMap = data[0].objectMap;
		var names = data[5];
		var i = names.length;
		
		while (i--) 
		{
			var name = names[i];
			vars.push(name);
			vars[name] = objectMap[name];
		}
	}
	/**
	 * 加载指定文本，找不到文件(404)返回null,调试时采用
	 * @friend
	 * @param {String} url 文件地址
	 * @return {String} 结果文本
	 */
	function loadTextByURL(url)
	{
		if ("org.xidea.jsi.boot:avoidBlock") 
		{
			var req = new XMLHttpRequest;
			req.open("GET", url, false);
			//for ie file 404 will throw exception
			req.send('');
			
			if (req.status >= 200 && req.status < 300 || req.status == 304 || !req.status) 
			{
				return req.responseText;
			}
			else 
			{
				return $log.error("loadTextByURL: load faild url: " + url + ' with code ' + req.status) || '';
			}
		}
	};
	/**
	 * 获取指定实现包(不存在则加载之)
	 * @intenal
	 * @param {String} packageObject 包对象
	 * @return {Package}
	 */
	function realPackage(packageObject)
	{
		if (":debug") 
		{
			if (!packageObject) 
			{
				if ("org.xidea.jsi.boot:$log") 
				{
					return $log.error("realPackage: get pkg error at " + realPackage.caller);
				}
			}
		}
		
		while (packageObject.implementation) 
		{
			packageObject = findPackage(packageObject.implementation, true);
		}
		return packageObject;
	}
	
	/**
	 * 获取指定包,抽象包也行(不存在则加载之)
	 * TODO:可编译优化 cacheAllPackage,不必探测空包
	 * @intenal
	 * @param {String} name 包名
	 * @param {boolean} exact 准确名，不需可上溯探测父包
	 * @return {Package}
	 */
	function findPackage(name, exact)
	{
		do 
		{
			if (packageMap[name]) 
			{
				return packageMap[name];
			}
			
			if (packageMap[name] === undefined) 
			{
				if (":debug") 
				{
					if ("org.xidea.jsi.boot:$log") 
					{
						$log.trace("findPackage: pkg: " + name);
					}
				}
				var pscript = getCachedScript(name, '') ||
				loadTextByURL(libBase + (name.replace(/\.|$/g, '/')) + '__package__.js');
				
				if (null != pscript) 
				{
				
					pscript == '' && $log.warn('findPackage: try to create undefined package: ' + name);
					return new Package(name, pscript);
				}
				//注册空包，避免重复探测hack for null
				packageMap[name] = 0;
			}
			
			if (exact) 
			{
				break;
			}
		}
		while (name = name.replace(/\.?[^\.]+$/, ''));
	}
	/**
	 * 获取指定对象路径的对应包
	 * @param {String} path 包路径
	 * @return {Package}
	 */
	function findPackageByPath(path)
	{
		$log.trace("findPackageByPath: at " + path);
		var p = path.lastIndexOf('/');
		
		return p > 0 ? findPackage(path.substr(0, p).replace(/\//g, '.'), true) : (p = path.indexOf(':')) > 0 ? findPackage(path.substr(0, p), true) : findPackage(path.replace(/\.?[^\.]+$/, ''));
	}
	/**
	 * 脚本装载器<b> &#160;(JSI 内部对象，普通用户不可见)</b>.
	 * 该对象的属性可以在JSI托管脚本内调用,但若使用了这些属性,脚本将无法脱离JSI环境(不可导出).
	 * <pre><code>eg:
	 *   var scriptBase = this.scriptBase;//获取当前脚本所在的目录
	 * </code></pre>
	 * @constructor
	 * @protected
	 * @implicit
	 * @param {Package} packageObject 包对象
	 * @param {String} fileName 脚本名
	 */
	function ScriptLoader(packageObject, fileName)
	{
		/**
		 * 脚本名，可在托管脚本顶层上下文（非函数内）访问，<code>this&#46;name</code>
		 * @friend
		 * @type {string}
		 */
		this.name = fileName;
		
		/**
		 * 脚本目录，可在托管脚本顶层上下文（非函数内）访问，<code>this&#46;scriptBase</code>
		 * @friend
		 * @type {string}
		 */
		this.scriptBase = packageObject.scriptBase;
		/**
		 * 脚本所属包名称，可在托管脚本顶层上下文（非函数内）访问，<code>this&#46;packageName</code>
		 * @friend
		 * @type {string}
		 */
		this.packageName = packageObject.name;
		/**
		 * 脚本的装载后依赖集合
		 * 脚本依赖键为0
		 * 对象依赖的键为对象名称
		 * 其与initialize共存亡
		 * @private
		 * @id ScriptLoader.prototype.dependenceMap
		 * @type {object}
		 */
		//this.dependenceMap = null;
		
		var loader = prepareScriptLoad(packageObject, this)
		
		if (loader) 
		{
			return loader;
		}
		doScriptLoad(packageObject, this);
	};
	
	/**
	 * 前期准备，初始化装载单元的依赖表，包括依赖变量申明，装载前依赖的装载注入
	 * @param {Package} packageObject
	 * @param {ScriptLoader} loader
	 * @internal
	 */
	function prepareScriptLoad(packageObject, loader)
	{
		var name = loader.name;
		var deps = packageObject.dependenceMap[name];
		var varText = 'this.hook=function(n){return eval(n)}';
		var vars = [];
		var i = deps && deps.length;
		
		while (i--) 
		{
			var dep = deps[i];
			var key = dep[3] || 0;
			
			if (dep[4]) 
			{
				vars.push.apply(vars, dep[5]);
				
				if (map) 
				{
					map[key] ? map[key].push(dep) : map[key] = [dep];
				}
				else 
				{
					var map = loader.dependenceMap = {};
					loader.initialize = scriptLoaderInitialize;
					map[key] = [dep];
				}
			}
			else 
			{
				loadDependence(dep, vars);
				
				if (dep = packageObject.loaderMap[name]) 
				{
					return dep;
				}
			}
		}
		
		if (vars.length) 
		{
			loader.varMap = vars;
			varText += ';var ' + vars.join(',').replace(/([^,]+)/g, '$1 = this.varMap.$1');
		}
		loader.varText = varText;
	}
	
	/**
	 * 装载脚本
	 * 这里没有依赖装载，装载前依赖装载在prepareScriptLoad中完成，装载后依赖在ScriptLoader.initialize中完成。
	 * @param {Package} packageObject
	 * @param {ScriptLoader} loader
	 * @internal
	 * @return {Object}
	 */
	function doScriptLoad(packageObject, loader)
	{
		var name = loader.name;
		var packageName = packageObject.name;
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.trace("doScriptLoad: pkg: " + packageName + " fileName:" + name);
			}
		}
		var cachedScript = getCachedScript(packageName, name);
		packageObject.loaderMap[name] = loader;
		
		try 
		{
			if (cachedScript instanceof Function) 
			{
				cachedScripts[packageName][name] = ''; //clear cache
				return cachedScript.call(loader);
			}
			else 
			{
				return freeEval.call(loader, 'eval(this.varText);' + (cachedScript || loadTextByURL(packageObject.scriptBase + name)));
			}
		} 
		catch (e) 
		{
			if (":debug") 
			{
				if ("org.xidea.jsi.boot:$log") 
				{
					$log.error("Load Error:\n" + loader.scriptBase + name + "\n\nException:" + e);
				}
			}
			throw e;
		}
		finally 
		{
			delete loader.varMap;
			delete loader.varText;
			var names = packageObject.scriptObjectMap[name];
			var index = names.length;
			var objectMap = packageObject.objectMap;
			
			if (index == 1) 
			{
				objectMap[names = names[0]] = loader.hook(names);
			}
			else 
			{
				var values = loader.hook('[' + names.join(',') + ']');
				
				while (index--) 
				{
					objectMap[names[index]] = values[index];
				}
			}
		}
	}
	
	/**
	 * 初始化制定对象，未指定代表全部对象，即当前装载单元的全部对象
	 * @param {String} object 对象名称
	 * @private
	 */
	function scriptLoaderInitialize(object)
	{
		var dependenceMap = this.dependenceMap;
		var vars = [];
		var name = this.name;
		var dependenceList = dependenceMap[0];
		
		if (dependenceList) 
		{
			//must use delete here
			delete dependenceMap[0];
			var i = dependenceList.length;
			while (i--) 
			{
				loadDependence(dependenceList[i], vars);
			}
		}
		if (object) 
		{
			if (dependenceList = dependenceMap[object]) 
			{
				delete dependenceMap[object];
				var i = dependenceList.length;
				
				while (i--) 
				{
					loadDependence(dependenceList[i], vars);
				}
			}
			
			for (var i in dependenceMap) 
			{
				break;
			}
			
			if (!i) 
			{
				this.dependenceMap = this.initialize = 0;
			}
		}
		else 
		{
			for (var object in dependenceMap) 
			{
				var dependenceList = dependenceMap[object];
				delete dependenceMap[object];
				var i = dependenceList.length;
				
				while (i--) 
				{
					loadDependence(dependenceList[i], vars);
				}
			}
			this.dependenceMap = this.initialize = 0;
		}
		
		if (vars.length) 
		{
			this.varMap = vars;
			vars = vars.join(',')
			this.hook(vars.replace(/([^,]+)/g, '$1 = this.varMap.$1'));
			delete this.varMap;
		}
	}
	
	/**
	 * 导入对象
	 * @param {Package} packageObject 包对象
	 * @param {String} objectName 对象名称
	 * @param {Object} target 目标对象
	 * @return {Object}
	 */
	function doObjectImport(packageObject, objectName, target)
	{
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.debug("doObjectImport: import " + objectName + " to " + target + " at package " + packageObject.name);
			}
		}
		//do load
		loadScript(packageObject, packageObject.objectScriptMap[objectName] || packageObject.addScript(objectName + ".js", objectName) || $log.warn("doObjectImport: try to add undefined object '" + objectName + "' at package " + packageObject.name) || packageObject.objectScriptMap[objectName], objectName, true);
		var pos2obj = objectName.indexOf('.');
		
		if (pos2obj > 0) 
		{
			objectName = objectName.substr(0, pos2obj);
		}
		pos2obj = packageObject.objectMap[objectName];
		return target != null ? target[objectName] = pos2obj : pos2obj;
	}
	/**
	 * 导入脚本
	 * @param {Package} packageObject 包对象
	 * @param {String} fileName 文件名称
	 * @param {Object} target 目标对象
	 */
	function doScriptImport(packageObject, fileName, target)
	{
		loadScript(packageObject, fileName);
		var objectNames = packageObject.scriptObjectMap[fileName];
		
		if (target != null) 
		{
			var i = objectNames.length;
			while (i--) 
			{
				target[objectNames[i]] = packageObject.objectMap[objectNames[i]];
			}
		}
	}
	if ("org.xidea.jsi.boot:col") 
	{
		/**
		 * 延迟加载
		 * @param {String} path 对象路径
		 * @param {Object} target 附着对象
		 * @param {Boolean|Function} col
		 */
		function lazyImport(path, target, col)
		{
			var pkg = findPackageByPath(path);
			var fileName = path.substr(pkg.name.length + 1);
			var list = [];
			var charPos, objName;
			if (":debug") 
			{
				if ("org.xidea.jsi.boot:$log") 
				{
					$log.debug("lazyImport: pkg: " + pkg.name + " with file: " + fileName);
				}
			}
			pkg = realPackage(pkg);
			
			//*代表包内全部对象
			if (fileName == '*') 
			{
				for (fileName in pkg.scriptObjectMap) 
				{
					appendCacheFiles(pkg, fileName);
				}
				//包内无定义,则尝试导入包名的最后部分.如example.test.undef.*,则导入undef.js->undef对象
				if ("*" == fileName) 
				{
					if (":debug") 
					{
						if ("org.xidea.jsi.boot:$log") 
						{
							$log.warn("lazyImport: try to import undefined pkg: " + pkg.name + " with file *");
						}
					}
					objName = pkg.name.substr(pkg.name.lastIndexOf(".") + 1);
					fileName = objName + ".js";
					pkg.addScript(fileName, objName);
					appendCacheFiles(pkg, fileName);
				}
			}
			//若导入为Ext.util.*这样的形式,则导入所有以Ext.util名称开始的对象
			else if (fileName.charAt(charPos = fileName.length - 1) == "*") 
			{
				var pName = fileName.substr(0, charPos);
				for (objName in pkg.objectScriptMap) 
				{
					if (objName.indexOf(pName) == 0) 
					{
						appendCacheFiles(pkg, pkg.objectScriptMap[objName], objName);
					}
				}
			}
			//单个文件或对象
			else 
			{
				//带路径的文件
				if (path.indexOf('/') + 1) 
				{
					appendCacheFiles(pkg, fileName);
				}
				//包内对象
				else 
				{
					appendCacheFiles(pkg, pkg.objectScriptMap[fileName] || pkg.addScript(fileName + ".js", fileName) || $log.warn("lazyImport: try to import undefined object '" + fileName + "' at package " + pkg.name) || pkg.objectScriptMap[fileName], fileName);
				}
			}
			//得到等待加载的文件列表
			for (var filePath in cacheFileMap) 
			{
				//path --> filePath
				if (!cacheFileMap[filePath][1]) 
				{
					cacheFileMap[filePath][1] = 1;
					list.push(filePath);
				}
			}
			
			if (col instanceof Function) 
			{
				function callback()
				{
					if (xhr.readyState == 4) 
					{
						$JSI.preload(pkg, fileName, xhr.responseText);
						//xhr.abort();
						setTimeout(next, 1);
					}
				}
				
				function next()
				{
					while (filePath = list.pop()) 
					{
						pkg = filePath.replace(/\/[^\/]+$/, '').replace(/\//g, '.');
						fileName = filePath.substr(pkg.length + 1);
						
						if (!getCachedScript(pkg, fileName)) 
						{
							xhr.open("get", libBase + filePath, true);
							xhr.onreadystatechange = callback;
							return xhr.send('');
						}
					}
					xhr.onreadystatechange = Function.prototype;
					col($import(path, target));
				}
				var xhr = new XMLHttpRequest;
				next();
			}
			else 
			{
				if (":debug") 
				{
					if (isLocal) 
					{
						try 
						{
							loadTextByURL(libBase + list[0].replace(/.js$/gm, "__preload__.js"));
							document.write(list.join("\n").replace(/.js$/gm, "__preload__.js").replace(/.+/g, "<script type='text/javascript' src='" + libBase + "$&' onerror=''></script>"));
						} 
						catch (e) 
						{
						}
					}
					//如果非本地模式则利用服务器端支持,动态加载文件,方便调试
					else 
					{
						document.write(list.join("\n").replace(/.+/g, "<script type='text/javascript' src='" + libBase + "?path=$&'></script>"));
					}
				}
				else 
				{
					document.write(list.join("\n").replace(/.js$/gm, "__preload__.js").replace(/.+/g, "<script type='text/javascript' src='" + libBase + "$&'></script>"))
				}
				lazyTaskList.push(function()
				{
					$import(path, target);
				});
				document.write(lazyScript);
			}
		}
	}
	return function(path, target, col)
	{
		switch (arguments.length)
		{
			//无参数时进行异步加载队列的处理
			case 0:
				col = lazyTaskList.shift();
				if (!(col instanceof Function)) 
				{
					if (":debug") 
					{
						if ("org.xidea.jsi.boot:$log") 
						{
							return $log.error("run lazyTaskList error with given " + col);
						}
					}
				}
				return col();
			//即时加载
			case 1:
				target = this;
				break;
			//若第二个参数为boolean或者function类型则认为时异步加载,否则同步导入对象到第二个参数[作为对象容器]
			case 2:
				switch (typeof target)
				{
					case 'boolean':
					case 'function':
						col = target;
						target = this;
				}
		}
		if ("org.xidea.jsi.boot:col") 
		{
			if (col) 
			{
				return lazyImport(path, target, col);
			}
		}
		//首先扫描路径是否被映射过,若映射过则替换为实际的路径
		var s;
		if (path && (s = mappedPath[path.replace(/[:\.].*/, "")])) 
		{
			path = path.replace(/^[^:\.]*/, s);
		}
		//如果路径末尾为:字符则认为是包对象,直接加载返回
		if (/\:$/.test(path)) 
		{
			return realPackage(findPackageByPath(path));
		}

		var pkg2obj = findPackageByPath(path);
		//得到对象名称(路径地址减去包名)
		var objectName = path.substr(pkg2obj.name.length + 1);
		if (":debug") 
		{
			if ("org.xidea.jsi.boot:$log") 
			{
				$log.debug("$import:" + pkg2obj.name + ":" + objectName);
			}
		}
		//如果路径中存在/字符,则认为是文件路径,进行导入脚本文件的操作
		if (path.indexOf('/') > -1) 
		{
			doScriptImport(realPackage(pkg2obj), objectName, pkg2obj = target);
		}
		//否则认为是包+对象名的方式
		else 
		{
			pkg2obj = realPackage(pkg2obj);
			
			if (objectName) 
			{
				//*代表导入包内所有对象
				if (objectName == '*') 
				{
					//reuse objectName as scriptName
					for (objectName in pkg2obj.scriptObjectMap) 
					{
						doScriptImport(pkg2obj, objectName, target);
					}
					//reuse pkg2obj variable
					pkg2obj = target;
				}
				else 
				{
					var charPos, objectTemp;
					//若导入为Ext.util.*这样的形式,则导入所有以Ext.util名称开始的对象
					if (objectName.charAt(charPos = objectName.length - 1) == "*") 
					{
						var pName = objectName.substr(0, charPos);
						for (objectName in pkg2obj.objectScriptMap) 
						{
							if (objectName.indexOf(pName) == 0) 
							{
								objectTemp = doObjectImport(pkg2obj, objectName, target);
							}
						}
						pkg2obj = objectTemp;
					}
					//导入pkg2obj包中的objectName对象
					else 
					{
						//reuse pkg2obj variable
						pkg2obj = doObjectImport(pkg2obj, objectName, target);
					}
				}
			}
		}
		return pkg2obj;
	}
}
(function(v)
{
	eval(v);
}, {});